//###############
//FILE : FileToNameSession.java
//WRITER : Daniel Lowengrub, daniel_i_l, 320687098
//EXERCISE : oop ex3 2011
//DESCRIPTION:
//See below
//###############
package oop.ex3.protocol.sessions;

import oop.ex3.protocol.messages.ContainFileMsg;
import oop.ex3.protocol.messages.BeginMsg;
import oop.ex3.protocol.messages.ContainNameServerMsg;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;

import oop.ex3.communication.SocketAddress;
import oop.ex3.exceptions.InvalidMessageException;

/**
 * This is the base class of all sessions from a FM to a NS. It's in provides methods
 * for starting and ending these kind of sessions as specified in the assignement.
 * @author daniel
 */
public abstract class FileToNameSession extends Session{
    protected ArrayList<String> _fileNames;
    protected ArrayList<SocketAddress> _nameServers;
    protected SocketAddress _fileManager;
    private static final String END_ERROR = "Invalid session termination:No final response from NameServer";

    /**
     * Create a new session.
     */
    public FileToNameSession() {
        super(new BeginMsg());
    }

    /**
     * Set the list of file name that will be sent to the NS during initialization.
     * @param fileNames The list of file names.
     */
    public void setFileNames(ArrayList<String> fileNames) {
        _fileNames = fileNames;
    }

    /**
     * Set the list of nameservers that will be sent to the NS during initialization.
     * @param fileNames The list of nameservers.
     */
    public void setNameServers(ArrayList<SocketAddress> nameServers) {
        _nameServers = nameServers;
    }

    /**
     * Set the address of the FM that's sending this session.
     * @param fileManager The FM address.
     */
    public void setFileManager(SocketAddress fileManager) {
        _fileManager = fileManager;
    }

    /**
     * Initialize a FM to NS session. It first sends a begin message. If it gets a welcome reply
     * then it sends its lists.
     * @param inputStream The sending stream.
     * @param outputStream The receiving stream.
     * @return True iff the initialization was successful.
     * @throws IOException If there were io problems.
     * @throws InvalidMessageException If an unexpected message was encountered.
     */
    protected boolean initSession(DataInputStream inputStream,
            DataOutputStream outputStream) throws IOException, InvalidMessageException {

        BeginMsg beginMsg = new BeginMsg(_fileManager);
        beginMsg.send(outputStream);

        if (_done.matchHeader(inputStream)) {
            _done.receive(inputStream);
            return true;
        }

        if (!_welcome.matchHeader(inputStream))
            return false;

        _welcome.receive(inputStream);

        //send file names
        for (String fileName : _fileNames) {
            ContainFileMsg containFile = new ContainFileMsg(fileName);
            containFile.send(outputStream);
            _done.receive(inputStream);
        }

        _endList.send(outputStream);
        _done.receive(inputStream);

        //send name servers
        for (SocketAddress addr : _nameServers) {
            ContainNameServerMsg containName = new ContainNameServerMsg(addr);
            containName.send(outputStream);
            _done.receive(inputStream);
        }

        _endList.send(outputStream);
        _done.receive(inputStream);

        return true;

    }

    /**
     * End an FM to NS session.
     * @param inputStream The sending stream.
     * @param outputStream The receiving stream.
     * @return True iff the ending was successful.
     * @throws IOException If there were io problems.
     * @throws InvalidMessageException If an unexpected message was encountered.
     */
    protected boolean endSession(DataInputStream inputStream,
            DataOutputStream outputStream) throws IOException, InvalidMessageException {

        //just send the end session message and get the done message
        _endSession.send(outputStream);
        try {
        	_done.receive(inputStream);
        } catch (Exception e) { //if we didn't get a done message then print an error
        	//e.printStackTrace();
        	System.out.println(END_ERROR);
        	return false;
        }

        return true;
    }


}
